﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using Bzure.Common.Patterns;
using Bzure.Common.Composition;
using Bzure.Common.Core;
using Bzure.Common.Data;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

[assembly: PreApplicationStartMethod(typeof(ContractFactoryFounder), "Start")]
namespace System
{

    public interface IContractFounder
    {
        void PluginContract(Dictionary<Type, object> MEFPool);
        void PluginManyContract(Dictionary<Type, Dictionary<string, object>> MEFManyPool);
    }
    public abstract class ContractFounderBase : IContractFounder
    {
        public abstract void PluginContract(Dictionary<Type, object> MEFPool);
        public abstract void PluginManyContract(Dictionary<Type, Dictionary<string, object>> MEFManyPool);
        public void PluginLazyContract<T>(IEnumerable<Lazy<T, IContractMetadata>> LazyLoaders, Dictionary<Type, Dictionary<string, object>> MEFManyPool)
        {
            Dictionary<string, object> dic = default(Dictionary<string, object>);
            if (!MEFManyPool.TryGetValue(typeof(T), out dic))
            {
                dic = new Dictionary<string, object>();
                MEFManyPool[typeof(T)] = dic;
            }

            foreach (Lazy<T, IContractMetadata> loader in LazyLoaders)
            {
                dic[loader.Metadata.ProviderName.ToLower()] = loader.Value;
            }
        }
        public void PluginNameContract<T>(string Key, T obj, Dictionary<Type, Dictionary<string, object>> MEFManyPool)
        {
            Dictionary<string, object> dic = default(Dictionary<string, object>);
            if (!MEFManyPool.TryGetValue(typeof(T), out dic))
            {
                dic = new Dictionary<string, object>();
                MEFManyPool[typeof(T)] = dic;
            }
            dic[Key.ToLower()] = obj;
        }
    }
    public static class ContractFactoryFounder
    {
        internal class FounderAgent : MEFContainerBase
        {
            [ImportMany]
            public IEnumerable<Lazy<IContractFounder, IContractMetadata>> ContractFounders;
            [ImportMany]
            public IEnumerable<Lazy<IContractFactory<IEntityRequestProcess>, IContractMetadata>> EntityProcessorBox;
            [ImportMany]
            public IEnumerable<Lazy<IContractFactory<IEntityPostProcess>, IContractMetadata>> EntityPostProcessorBox;
            [ImportMany]
            public IEnumerable<Lazy<IApplicationStart, IContractMetadata>> _appStarts;


            //protected override string MapPath(string virtualPath)
            //{
            //    return HttpContext.Current.Server.MapPath(virtualPath);
            //}

        }
        class GlobalObject
        {
        }
        static GlobalObject _globalObject = new GlobalObject();
        static FounderAgent _founderAgent;

        static Dictionary<Type, object> MEFPool = new Dictionary<Type, object>();
        static Dictionary<Type, Dictionary<string, object>> MEFManyPool = new Dictionary<Type, Dictionary<string, object>>();
        //static Dictionary<string, IContractFactory<IEntityRequestProcess>> EntityProcessorPool = new Dictionary<string, IContractFactory<IEntityRequestProcess>>();

        static List<ComposablePartCatalog> catalogs = new List<ComposablePartCatalog>();
        public static void AddCatalog(ComposablePartCatalog item)
        {
            catalogs.Add(item);
        }
        public static void Start()
        {
            _founderAgent = new FounderAgent();
            _founderAgent.Compose(catalogs);
            ApplicationStartContext AppContext = new ApplicationStartContext();

            foreach (Lazy<IContractFounder, IContractMetadata> lazyFounder in _founderAgent.ContractFounders)
            {
                try
                {
                    lazyFounder.Value.PluginContract(MEFPool);
                }
                catch
                {
                }
                try
                {
                    lazyFounder.Value.PluginManyContract(MEFManyPool);
                }
                catch
                {
                }
            }
            foreach (Lazy<IApplicationStart, IContractMetadata> lazyStarter in _founderAgent._appStarts.OrderBy(m => m.Value.ContractVersion))
            {
                try
                {
                    lazyStarter.Value.PreStart(AppContext);
                }
                catch
                {
                }
            }
            foreach (Lazy<IApplicationStart, IContractMetadata> lazyStarter in _founderAgent._appStarts.OrderBy(m => m.Value.ContractVersion))
            {
                try
                {
                    lazyStarter.Value.Start(AppContext);
                }
                catch
                {
                }
            }

        }


        public static T GetExport<T>(this Public Public) where T : class
        {
            object obj = default(T);
            if (MEFPool.TryGetValue(typeof(T), out obj) && obj is T)
            {
                return obj as T;
            }
            return default(T);
        }
        public static T[] GetManyExports<T>(this Public Public) where T : class
        {
            Dictionary<string, object> obj = default(Dictionary<string, object>);
            if (MEFManyPool.TryGetValue(typeof(T), out obj) && obj is Dictionary<string, object>)
            {
                List<T> list = new List<T>();
                foreach (object o in obj.Values)
                {
                    list.Add(o as T);
                }
                return list.ToArray();
            }
            return default(T[]);
        }
        public static T GetNamedExport<T>(this Public Public, string ProviderName) where T : class
        {
            Dictionary<string, object> obj = default(Dictionary<string, object>);
            if (MEFManyPool.TryGetValue(typeof(T), out obj) && obj is Dictionary<string, object>)
            {
                object o = null;
                if (obj.TryGetValue(ProviderName.ToLower(), out o))
                {
                    return o as T;
                }
            }
            return default(T);
        }
        public static T BuildContractProvider<T>(this Public Public) where T : class
        {
            object obj = default(IContractFactory<T>);
            if (MEFPool.TryGetValue(typeof(IContractFactory<T>), out obj) && obj is IContractFactory<T>)
            {
                IContractFactory<T> builder = obj as IContractFactory<T>;
                return builder.Build().AsDecorator();
            }
            return default(T);
        }
        public static IEntityRequestProcess BuildEntityProcessor(this Public Public, string ProviderName)
        {
            Lazy<IContractFactory<IEntityRequestProcess>> factoryLazy = _founderAgent.EntityProcessorBox.FirstOrDefault(f => f.Metadata.ProviderName.Equals(ProviderName, StringComparison.InvariantCultureIgnoreCase));
            IContractFactory<IEntityRequestProcess> factory = factoryLazy.Value;
            if (factory != default(IContractFactory<IEntityRequestProcess>))
            {
                return factory.Build();
            }
            return default(IEntityRequestProcess);
        }
        public static IEntityPostProcess BuildEntityPostProcessor(this Public Public, string ProviderName)
        {
            Lazy<IContractFactory<IEntityPostProcess>> factoryLazy = _founderAgent.EntityPostProcessorBox.FirstOrDefault(f => f.Metadata.ProviderName.Equals(ProviderName, StringComparison.InvariantCultureIgnoreCase));
            IContractFactory<IEntityPostProcess> factory = factoryLazy.Value;
            if (factory != default(IContractFactory<IEntityPostProcess>))
            {
                return factory.Build();
            }
            return default(IEntityPostProcess);
        }
    }
}
